﻿using System;
using System.Globalization;
using System.Linq;
using System.Web.UI.WebControls;
using Medianamik.Core;
using Medianamik.Core.DAL;
using Medianamik.Core.DAL.Repositories;
using Medianamik.Core.Sugar;
using Medianamik.UI.Web.MVP.View;

namespace Medianamik.UI.Web.MVP.Presentation
{
    public abstract class ModulePresenterWithDefaultFilters<TItem, TView, TRepository> :
        ModulePresenterWithRepository<TItem, TView, TRepository>
        where TItem : class, IMedianamikDTO
        where TView : IViewWithDefaultFilters
        where TRepository : class, IRepositoryWithDefaultFilters<TItem>
    {
        public ModulePresenterWithDefaultFilters(TView view, TRepository repository)
            : base(view, repository)
        {

        }

        private int? _status;
        protected virtual int Status
        {
            get { return _status ?? (_status = GetStatus()).GetValueOrDefault(DefaultStatus); }
        }
        protected virtual int? GetStatus()
        {
            return View.IsPostBack ? SelectedStatus : View.QueryString.GetValue<int?>("status");
        }
        protected virtual int DefaultStatus { get { return 2; } }

        private DateTime? _start;
        protected virtual DateTime? Start
        {
            get { return _start ?? (_start = GetStart() ?? DefaultStart); }
        }
        protected virtual DateTime? GetStart()
        {
            return View.IsPostBack ? View.SelectedStartDateTime :
                View.QueryString.GetValue<long?>("start") == null ? default(DateTime?) :
                    new DateTime(View.QueryString.GetValue<long?>("start").Value);
        }
        protected virtual DateTime? DefaultStart { get { return null; } }

        private int? _pageIndex;
        protected virtual int PageIndex
        {
            get { return _pageIndex ?? (_pageIndex = GetPageIndex()).GetValueOrDefault(1); }
        }
        protected virtual int? GetPageIndex()
        {
            return View.IsPostBack ? View.PageIndex : View.QueryString.GetValue<int?>("pageindex");
        }

        private int? _pageSize;
        protected virtual int PageSize
        {
            get { return _pageSize ?? (_pageSize = GetPageSize()).GetValueOrDefault(DefaultPageSize); }
        }
        protected virtual int? GetPageSize()
        {
            return View.IsPostBack ? View.PageSize : View.QueryString.GetValue<int?>("pagesize");
        }
        protected virtual int DefaultPageSize { get { return 10; } }

        private DateTime? _end;
        protected virtual DateTime? End
        {
            get { return _end ?? (_end = GetEnd() ?? DefaultEnd); }
        }
        protected virtual DateTime? GetEnd()
        {
            return View.IsPostBack ? View.SelectedEndDateTime :
                View.QueryString.GetValue<long?>("end") == null ? default(DateTime?) :
                    new DateTime(View.QueryString.GetValue<long?>("end").Value);
        }
        protected virtual DateTime? DefaultEnd { get { return null; } }

        private string _keywords;
        protected virtual string Keywords
        {
            get { return _keywords ?? (_keywords = GetKeywords()) ?? DefaultKeywords; }
        }
        protected virtual string GetKeywords()
        {
            return View.IsPostBack ? View.Keywords : View.QueryString.GetValue<string>("keywords");
        }
        protected virtual string DefaultKeywords { get { return ""; } }
        
      

        protected virtual bool HasMultipleTypes { get { return false; } }

        protected virtual void NodeDeleted(object sender, EventArgs e)
        {
            Bind();
        }

        protected virtual void LockRequestFailed(object sender, IdEventArgs e)
        {
            View.ShowLockInfoTooltip(e.Id);
            Bind();
        }

        protected virtual void ActivationStatusChanged(object sender, ActivationStatusChangedEventArgs e)
        {
            Repository.SetActiveStatus(e.Id, e.Culture, e.Status);
            Bind();
        }

        protected virtual string AddUrl
        {
            get
            {
                return EditPage
                    .AddParam("parentid", ModuleNodeId)
                    .AddParam("typeid", BaseTypeId)
                    .AddParam("returnurl", EditReturnURL)
                    .AddParam("hidetreeview", true);
            }
        }

        protected abstract Guid ModuleNodeId { get; }
        protected abstract Guid BaseTypeId { get; }

        protected virtual void PageSizeChanged(object sender, NumericalEventArgs e)
        {
            if(e.Number.HasValue)
                View.PageSize = e.Number.Value;
            Bind(null, null, null, null, null, e.Number);
        }

        protected virtual void PageIndexChanged(object sender, PageIndexChangedEventArgs e)
        {
            View.PageIndex = e.PageId;
            Bind(e.MustLoadData, null, null, null, null, e.PageId, null);
        }

        protected virtual void Rebind(object sender, EventArgs e)
        {
            View.PageIndex = 1;
            Bind();
        }

        protected virtual void Bind()
        {
            Bind(null, null, null, null, null, null);
        }
        protected virtual void Bind(int? selectedStatus, string keywords, DateTime? startDate,
            DateTime? endDate, int? pageIndex, int? pageSize)
        {
            Bind(true, selectedStatus, keywords, startDate, endDate, pageIndex, pageSize);
        }
        protected virtual void Bind(bool mustLoadData, int? selectedStatus, string keywords, DateTime? startDate,
            DateTime? endDate, int? pageIndex, int? pageSize)
        {
            var newPageIndex = pageIndex ?? View.PageIndex;
            var newPageSize = pageSize ?? View.PageSize;
            var newStatus = selectedStatus ?? SelectedStatus;
            var newKeywords = keywords ?? View.Keywords;
            var newStartDate = startDate ?? View.SelectedStartDateTime;
            var newEndDate = endDate ?? View.SelectedEndDateTime;

            if (newPageSize < 1)
                throw new Exception("Page size must be higher than 0.");

            View.EditReturnUrl = "&returnurl=" + BuildReturnUrl(ListingPage,
                newStatus, newKeywords, newStartDate, newEndDate, newPageIndex, newPageSize).UrlEncodeBase64();

            if (mustLoadData)
            {
                var paged = PagedWithFilters(CurrentEditionCulture, newPageIndex,
                     newPageSize, (ActiveStatus)newStatus.GetValueOrDefault(),
                     newStartDate.ToStartingComparedDate(),
                     newEndDate.ToEndingComparedDate(), newKeywords);

                View.TotalCount = paged.TotalCount;
                View.DataSource = paged.Collection.Cast<IMedianamikDTO>();
            }
        }

        protected abstract string ListingPage { get; }

        protected virtual string EditPage { get { return Pages.ContentManagementEdition; } }

        protected virtual PagedCollection<TItem> GetData()
        {
            return Repository.PagedWithFilters(CurrentEditionCulture, PageIndex, PageSize, 
                (ActiveStatus)Status, BaseTypeId, ModuleNodeId, Start.ToStartingComparedDate(), 
                End.ToEndingComparedDate(), Keywords);
        }

        protected virtual void ValidateArguments()
        {
            if (PageSize < 1)
                throw new Exception("Page size must be higher than 0.");

            if (Status < 0 || Status > 2)
                throw new Exception("Status must be between 0 and 2.");
        }

        protected virtual PagedCollection<TItem> PagedWithFilters(CultureInfo editionCulture,
            int pageIndex, int pageSize, ActiveStatus contentStatus, DateTime? startingCreatedOn,
            DateTime? endingCreatedOn, string keywords)
        {

            return Repository.PagedWithFilters(editionCulture, pageIndex, pageSize, contentStatus,
                 BaseTypeId, ModuleNodeId, startingCreatedOn, endingCreatedOn, keywords);
        }

        protected virtual void BindStatus(int? selectedStatus)
        {
            var options = new[] { new ListItem("Tous", "2"), new ListItem("Actif", "0"), new ListItem("Inactif", "1") };

            if (selectedStatus.HasValue)
            {
                options.First(i => i.Value.Equals(selectedStatus.ToString())).Selected = true;
            }

            View.Status = options;
        }

        protected virtual string BuildUrl(string pageUrl, string paramName, Guid nodeId)
        {
            return pageUrl.AddParam(paramName, nodeId).AddParam("returnurl", EditReturnURL);
        }

        protected virtual string BuildReturnUrl()
        {
            var returlUrl = ListingPage;

            if (View.AllowPaging)
            {
                if (PageIndex != 1)
                    returlUrl = returlUrl.AddParam("pageindex", PageIndex);

                if (PageSize != DefaultPageSize)
                    returlUrl = returlUrl.AddParam("pagesize", PageSize);
            };

            if (Status != DefaultStatus)
            {
                returlUrl = returlUrl.AddParam("status", Status);
            }

            if (Keywords != DefaultKeywords)
            {
                returlUrl = returlUrl.AddParam("keywords", Keywords.UrlEncode());
            }

            if (Start != DefaultStart)
            {
                returlUrl = returlUrl.AddParam("start", Start.Value.Ticks);
            }

            if (End != DefaultEnd)
            {
                returlUrl = returlUrl.AddParam("end", End.Value.Ticks);
            }

            return returlUrl;
        }

        private bool _selectedStatusIsRetreived;
        private int? GetSelectedStatus()
        {
            _selectedStatusIsRetreived = true;
            var selectedTheme = View.Status.FirstOrDefault(i => i.Selected) ??
                View.Status.FirstOrDefault();

            int? status = null;

            if (selectedTheme != null && !String.IsNullOrEmpty(selectedTheme.Value))
                status = int.Parse(selectedTheme.Value);

            return status;
        }
        private int? _selectedStatus;
        protected virtual int? SelectedStatus
        {
            get
            {
                if (_selectedStatusIsRetreived)
                    return _selectedStatus;

                return _selectedStatus = GetSelectedStatus();
            }
        }

        protected virtual CultureInfo CurrentEditionCulture
        {
            get { return View.CurrentEditionCulture; }
        }

        protected virtual CultureInfo CurrentUICulture
        {
            get { return View.CurrentUICulture; }
        }

        private string _editReturnURL;
        protected string EditReturnURL
        {
            get { return _editReturnURL ?? (_editReturnURL = BuildReturnUrl()); }
        }
    }
}